import { AcGameObject } from "./AcGameObject";
import { Snake } from "./Snake";
import { Wall } from "./Wall";

export class GameMap extends AcGameObject {
    constructor(ctx, parent) {
        super();

        this.ctx = ctx;
        this.parent = parent;
        this.L = 0;

        this.rows = 13;
        this.cols = 13;

        this.inner_walls_count = 12;

        this.walls = [];
        this.create_walls(); // ✅ 在构造时创建墙

        this.snakes = [
            new Snake({id: 0, color: "#4876EC", r: this.rows - 2, c: 1}, this),
            new Snake({id: 1, color: "#F94848", r: 1, c: this.cols - 2}, this)
        ];
    }

    create_walls() {
    const g = [];
    for (let r = 0; r < this.rows; r++) {
        g[r] = [];
        for (let c = 0; c < this.cols; c++) {
            g[r][c] = false;
        }
    }

    // 边界墙：四周
    for (let r = 0; r < this.rows; r++) {
        g[r][0] = g[r][this.cols - 1] = true;
    }
    for (let c = 0; c < this.cols; c++) {
        g[0][c] = g[this.rows - 1][c] = true;
    }

    // 起点和终点：必须为空（且对称）
    const startR = this.rows - 2, startC = 1;   // 左下附近
    const endR = 1, endC = this.cols - 2;       // 右上附近
    g[startR][startC] = false;
    g[endR][endC] = false;
    // 对称点也要清空（虽然它们可能就是彼此）
    g[startC][startR] = false;
    g[endC][endR] = false;

    // 所有可选的内墙位置（对称对）
    const candidates = [];
    for (let r = 1; r < this.rows - 1; r++) {
        for (let c = 1; c < this.cols - 1; c++) {
            // 跳过起点/终点及其对称点
            if ((r === startR && c === startC) ||
                (r === endR && c === endC) ||
                (r === startC && c === startR) ||
                (r === endC && c === endR)) {
                continue;
            }
            // 只考虑上三角（避免重复对称对）
            if (r <= c) {
                candidates.push([r, c]);
            }
        }
    }

    // 随机打乱
    for (let i = candidates.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [candidates[i], candidates[j]] = [candidates[j], candidates[i]];
    }

    // BFS 检查连通性函数
    const isConnected = (grid) => {
        const visited = Array(this.rows).fill().map(() => Array(this.cols).fill(false));
        const queue = [[startR, startC]];
        visited[startR][startC] = true;

        const dirs = [[-1,0],[1,0],[0,-1],[0,1]];

        while (queue.length) {
            const [r, c] = queue.shift();
            if (r === endR && c === endC) return true;
            for (const [dr, dc] of dirs) {
                const nr = r + dr, nc = c + dc;
                if (nr >= 0 && nr < this.rows && nc >= 0 && nc < this.cols &&
                    !visited[nr][nc] && !grid[nr][nc]) {
                    visited[nr][nc] = true;
                    queue.push([nr, nc]);
                }
            }
        }
        return false;
    };

    let placed = 0;
    for (const [r, c] of candidates) {
        if (placed >= this.inner_walls_count) break;

        // 尝试放置对称墙
        const originalRC = g[r][c];
        const originalCR = g[c][r];

        g[r][c] = true;
        g[c][r] = true;

        // 检查是否仍连通
        if (isConnected(g)) {
            placed++;
        } else {
            // 回滚
            g[r][c] = originalRC;
            g[c][r] = originalCR;
        }
    }

    // 构建 walls 数组
    this.walls = [];
    for (let r = 0; r < this.rows; r++) {
        for (let c = 0; c < this.cols; c++) {
            if (g[r][c]) {
                this.walls.push(new Wall(r, c, this));
            }
        }
    }
    }

    add_listening_event(){
        this.ctx.canvas.focus();

        const [snake0, snake1] = this.snakes;
        this.ctx.canvas.addEventListener("keydown", e => {
            if(e.key === 'w') snake0.set_direction(0);
            else if(e.key === 'd') snake0.set_direction(1);
            else if(e.key === 's') snake0.set_direction(2);
            else if(e.key === 'a') snake0.set_direction(3);
            else if(e.key ==='ArrowUp') snake1.set_direction(0);
            else if(e.key ==='ArrowRight') snake1.set_direction(1);
            else if(e.key ==='ArrowDown') snake1.set_direction(2);
            else if(e.key ==='ArrowLeft') snake1.set_direction(3);
        });
    }

    start() {
        // 如果需要延迟初始化，也可以在这里调用 create_walls()
        this.add_listening_event();
    }

    update_size() {
        const width = this.parent.clientWidth;
        const height = this.parent.clientHeight;

        // 取整：确保 L 是整数像素
        this.L = Math.floor(Math.min(
            width / this.cols,
            height / this.rows
        ));

        this.ctx.canvas.width = this.L * this.cols;
        this.ctx.canvas.height = this.L * this.rows;
    }

    check_ready(){ //判断两条蛇是否准备好下一回合
        for(const snake of this.snakes){
            if(snake.status != "idle") return false;
            if(snake.direction === -1) return false;
        }
        return true;
    }

    next_step(){ //让两条蛇进入下一回合
        for(const snake of this.snakes){
            snake.next_step();
        }
    }

    check_valid(cell){ //检查目标位置是否合法：没有撞到两条蛇的身体和障碍物
        for(const wall of this.walls){
            if(wall.r === cell.r && wall.c === cell.c)
                return false;
        }
        
        for(const snake of this.snakes){
            let k = snake.cells.length;
            if(!snake.check_tail_increasing()){ //当蛇尾会前进的时候，蛇尾不要判断
                k--;
            }
            for(let i = 0; i < k; i++){
                if(snake.cells[i].r === cell.r && snake.cells[i].c === cell.c)
                    return false;
            }
        }
        return true;
    }

    update() {
        this.update_size();

        if(this.check_ready()){
            this.next_step();
        }

        this.render();

        // ✅ 必须更新并渲染所有墙
        for (const wall of this.walls) {
            wall.update(); // Wall.update() 会调用 render()
        }
    }

    render() {
        const color_even = "#AAD751", color_odd = "#A2D149";
        for (let r = 0; r < this.rows; r++) {
            for (let c = 0; c < this.cols; c++) {
                this.ctx.fillStyle = (r + c) % 2 === 0 ? color_even : color_odd;
                this.ctx.fillRect(c * this.L, r * this.L, this.L, this.L);
            }
        }
    }
}
